//-----------------------------------------------------------------------
// <author>Paul Long</author>
//-----------

using System.IO;

[assembly: System.Security.Permissions.EnvironmentPermissionAttribute(System.Security.Permissions.SecurityAction.RequestRefuse, Unrestricted = true)]
[assembly: System.CLSCompliant(false)]
namespace NMTopUsers
{
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using NetworkAddresses;
    using TopUserCharts;
    using TopUserExceptions;

    /// <summary>
    /// <para>The UI can be run in one of two modes: Endpoint or Conversation.
    /// </para>
    /// <para>Endpoint mode shows each IPv4, IPv6 or Ethernet address and it's stats: bytes/frames sent/received/total.
    /// </para>
    /// <para>Conversation mode shows the same information between a 'source' and 'destination' address. The first 
    /// frame of a conversation found in the capture file determines the 'source' and 'destination' addresses. The
    /// 'Sent' statistics are for data going from 'source' to 'destination' address, and the 'Received' statistics
    /// are for data going from the 'destination' to the 'source' address. The '% Total Bytes', '% Bytes Sent' and 
    /// '% Bytes Rcvd' columns are only visible when a single 'Address type' is selected.
    ///  </para>
    /// <para>There is a File > Open option to select and open a capture file for analysis.
    /// </para>
    /// <para>There is a Mode option to switch between Endpoint and Conversation mode.
    /// </para>
    /// <para>There are options to show IPv4/IPv6/Ethernet from the menu bar.
    /// </para>
    /// <para>There is an option to display the data as a tree so that Ipv4/IPv6 addresses appear under
    /// the Ethernet address they are sent from.
    /// </para>
    /// <para>There are two tool bar menu items to display the data as a pie or bar chart.
    /// </para>
    /// <para>Data can be sorted on any column.  An order column is added in tree mode so that the
    /// original alignment can be reset.
    /// </para>
    /// <para>A row can be right clicked to copy it's NM3 ready filter into the clipboard.
    /// </para>
    /// <para>A set of rows can be right clicked and copied as tab separated into the clipboard.
    /// </para>
    /// </summary>
    public partial class TopUsers : Form, IDisposable
    {
        #region States
        public enum OperationMode
        {
            Endpoint,
            Conversation
        }

        // Used to index into the TUGrid.Columns[] array.
        public enum GridColumnName
        {
            Address = 0,
            ToAddress,
            TotalBytes,
            PctTotalBytes,
            TotalFrames,
            BytesSent,
            PctBytesSent,
            FramesSent,
            KbpsSent,
            BytesRcvd,
            PctBytesRcvd,
            FramesRcvd,
            KbpsRcvd,
            Delta,
            Order
        }

        /// <summary>
        /// Whether we are in Endpoint or Conversation mode.
        /// </summary>
        private OperationMode mode;

        /// <summary>
        /// The full path to the capture file to analyze.
        /// </summary>
        private string captureFile;

        /// <summary>
        /// Combined display and conversation filter
        /// </summary>
        private string combinedFilter;

        /// <summary>
        /// Parses and contains all the capture data as returned from the NMAPI.
        /// </summary>
        private NetworkMonitorData networkMonitorData;
        #endregion States

        #region Methods
        /// <summary>
        /// Initializes a new instance of the TopUsers class.  
        /// Records the Command Line parameters.
        /// </summary>
        /// <param name="captureFile">Capture file to process.</param>
        /// <param name="combinedFilter">Combined display and conversation filter.</param>
        /// <param name="mode">Determine conversation or endpoint mode.</param>
        public TopUsers(string captureFile, string combinedFilter, OperationMode mode)
        {
            this.captureFile = captureFile;
            this.combinedFilter = combinedFilter;

            this.InitializeComponent();

            // Must call SetCurrentMode() after this.InitializeComponent().
            SetCurrentMode(mode);

            InfoStatusLabel.Text = string.Empty;
        }

        /// <summary>
        /// Set whether we are in "Conversation" or "Endpoint" mode.
        /// </summary>
        private void SetCurrentMode(OperationMode mode)
        {
            this.mode = mode;
            this.modeByConversation.Checked = (mode == OperationMode.Conversation);
            this.modeByEndpoint.Checked = (mode == OperationMode.Endpoint);
        }

        /// <summary>
        /// Instantiates a chart control.  Caller wraps with an exception handler
        /// to determine if the appropriate control is installed.
        /// </summary>
        private static void ChartControlInstalled()
        {
            System.Windows.Forms.DataVisualization.Charting.ChartArea testChartArea;
            testChartArea = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
            testChartArea.Dispose();
        }

        /// <summary>
        /// Provides coordinates so that dialogs are centered in relationship to
        /// the main window.
        /// </summary>
        /// <param name="width">Width of the dialog</param>
        /// <returns>A coordinates of upper left hand corner for dialog.</returns>
        private Point CenterDialog(int width)
        {
            int x = (this.Width / 2) - (width / 2) + this.Location.X;
            int y = this.Location.Y + 10;

            return new Point(x, y);
        }

        /// <summary>
        /// Enables the tree if the right conditions are met.
        /// </summary>
        private void EnableTree()
        {
            if ((this.ipv6Show.Checked || this.ipv4Show.Checked) && this.ethernetShow.Checked)
            {
                this.Tree.Enabled = true;
                if (this.Tree.Checked)
                {
                    this.ResetTreeButton.Enabled = true;
                }
            }
            else
            {
                this.Tree.Enabled = false;
                this.ResetTreeButton.Enabled = false;
            }
        }

        /// <summary>
        /// Load and parse the capture file and fill the grid.
        /// </summary>
        private void LoadDataAndDisplayGrid()
        {
            TUGrid.Rows.Clear();
            LoadStatusLabel.Visible = true;
            LoadProgressBar.Visible = true;
            LoadStatusLabel.Text = "Working ...";
            InfoStatusLabel.Text = string.Empty;

            // This timer hack is the only way I could get the grid to visibly clear while the capture
            // file is loaded and parsed.
            this.timer1.Interval = 5;           // A short delay to allow the UI to visually catch up.
            this.timer1.Enabled = true;
        }

        /// <summary>
        /// The timer has ticked, so load the capture file and display the data in the grid.
        /// </summary>
        private void Timer1Tick(object sender, EventArgs e)
        {
            this.timer1.Enabled = false;

            LoadDataAndDisplayGrid_Internal();
        }

        /// <summary>
        /// Called by the timer tick event to load the capture file and display the data in the grid.
        /// </summary>
        private void LoadDataAndDisplayGrid_Internal()
        {
            this.Text = string.Format(
                            CultureInfo.CurrentCulture,
                            "Top Users {1} - {0} - {2}",
                            this.captureFile,
                            this.mode==OperationMode.Conversation ? "by Conversation" : "by Endpoint",
                            string.IsNullOrEmpty(this.combinedFilter) ? "Not Filtered" : "Filtered");

            try
            {
                if (this.networkMonitorData != null)
                {
                    this.networkMonitorData.Dispose();
                }
                this.networkMonitorData = new NetworkMonitorData(this.combinedFilter, this.mode);

                if (NetworkMonitorData.ErrorsExist)
                {
                    MessageBox.Show(
                                    NetworkMonitorData.GetErrors,
                                    "Build Errors",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Information,
                                    MessageBoxDefaultButton.Button1,
                                    MessageBoxOptions.DefaultDesktopOnly);
                    MessageBox.Show(
                                    "Please Fix Parser Errors and restart",
                                    "Build Errors",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Information,
                                    MessageBoxDefaultButton.Button1,
                                    MessageBoxOptions.DefaultDesktopOnly);

                    this.Close();
                }
                else
                {
                    if (!string.IsNullOrEmpty(this.captureFile))
                    {
                        this.EnableTree();

                        if (this.networkMonitorData.LoadCapture(this.captureFile, LoadStatusLabel, LoadProgressBar, this))
                        {
                            TUGrid.UseWaitCursor = true;

                            TUGrid.Columns[(int)GridColumnName.Delta].Visible = false;  // Don't need delta column

                            TUGrid.Columns[(int)GridColumnName.ToAddress].Visible = (this.mode == OperationMode.Conversation);

                            this.networkMonitorData.FillGrid(TUGrid, ipv4Show.Checked, ipv6Show.Checked, ethernetShow.Checked, Tree.Checked);

                            TUGrid.Sort(TUGrid.Columns[(int)GridColumnName.Address], ListSortDirection.Ascending);

                            TUGrid.Columns[(int)GridColumnName.Order].Visible = false;
                            if (!Tree.Checked)
                            {
                                TUGrid.Sort(TUGrid.Columns[(int)GridColumnName.TotalBytes], ListSortDirection.Descending);
                            }
                            else
                            {
                                TUGrid.Sort(TUGrid.Columns[(int)GridColumnName.Order], ListSortDirection.Ascending);
                            }

                            TUGrid.UseWaitCursor = false;

                            InfoStatusLabel.Text = this.networkMonitorData.DisplayedFramesStartEndTimes;

                            // Set the window width, but not the height.
                            Size totSize = TUGrid.PreferredSize;
                            totSize.Height = this.Size.Height;

                            this.Size = totSize;
                        }
                    }
                }

                SetupGrid();

                LoadStatusLabel.Visible = false;
                LoadProgressBar.Visible = false;
            }
            catch (ParsingException exception)
            {
                MessageBox.Show(
                                "Error loading " + exception.Message,
                                "Parser Loading Error",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                MessageBoxOptions.DefaultDesktopOnly);

                this.Close();
            }
        }

        /// <summary>
        /// Make the appropraite grid columns visible as appropriate.
        /// </summary>
        private void SetupGrid()
        {
            // Only show the percentage columns for conversations where only one address type is selected.
            int numShown = 0;
            bool showPercentages = false;
            if (ipv4Show.Checked)
                numShown++;
            if (ipv6Show.Checked)
                numShown++;
            if (ethernetShow.Checked)
                numShown++;
            if (numShown == 1  &&  this.mode == OperationMode.Conversation)
                showPercentages = true;

            TUGrid.Columns[(int)GridColumnName.PctTotalBytes].Visible = showPercentages;
            TUGrid.Columns[(int)GridColumnName.PctBytesSent].Visible = showPercentages;
            TUGrid.Columns[(int)GridColumnName.PctBytesRcvd].Visible = showPercentages;

            // Show the frame count columns when not showing percentages.
            TUGrid.Columns[(int)GridColumnName.TotalFrames].Visible = !showPercentages;
            TUGrid.Columns[(int)GridColumnName.FramesSent].Visible = !showPercentages;
            TUGrid.Columns[(int)GridColumnName.FramesRcvd].Visible = !showPercentages;

            // Set the window width to accomodate the columns in the grid.
            Size totSize = this.TUGrid.PreferredSize;
            totSize.Height = this.Size.Height;
            this.Size = totSize;
        }

        /// <summary>
        /// Handle the File > Open menu click.
        /// </summary>
        private void FileOpen_Click(object sender, EventArgs e)
        {
            openFileDialog1.FileName = this.captureFile;

            openFileDialog1.InitialDirectory = Path.GetDirectoryName(this.captureFile);
            openFileDialog1.Filter = "Capture files (*.cap)|*.cap|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                this.captureFile = openFileDialog1.FileName;

                LoadDataAndDisplayGrid();
            }
        }

        /// <summary>
        /// When the IPv4 box is checked on/off, we refill the grid and sort the data.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void IPv4Show_Click(object sender, EventArgs e)
        {
            this.ipv4Show.Checked = !this.ipv4Show.Checked;
            this.networkMonitorData.FillGrid(this.TUGrid, this.ipv4Show.Checked, this.ipv6Show.Checked, 
                                             this.ethernetShow.Checked, this.Tree.Checked);
            this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.Address], ListSortDirection.Ascending);

            this.EnableTree();

            if (this.Tree.Checked && this.Tree.Enabled)
            {
                this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.Order], ListSortDirection.Ascending);
            }
            else
            {
                this.TUGrid.Columns[(int)GridColumnName.Order].Visible = false;
                this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.TotalBytes], ListSortDirection.Descending);
            }

            SetupGrid();
        }

        /// <summary>
        /// When the IPv6 box is checked on/off, we refill the grid and sort the data.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void IPv6Show_Click(object sender, EventArgs e)
        {
            this.ipv6Show.Checked = !this.ipv6Show.Checked;
            this.networkMonitorData.FillGrid(this.TUGrid, this.ipv4Show.Checked, this.ipv6Show.Checked, 
                                             this.ethernetShow.Checked, this.Tree.Checked);
            this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.Address], ListSortDirection.Ascending);

            this.EnableTree();

            if (this.Tree.Checked && this.Tree.Enabled)
            {
                this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.Order], ListSortDirection.Ascending);
            }
            else
            {
                this.TUGrid.Columns[(int)GridColumnName.Order].Visible = false;
                this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.TotalBytes], ListSortDirection.Descending);
            }

            SetupGrid();
        }

        /// <summary>
        /// When the Ethernet box is checked on/off, we refill the grid and sort the data.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void EthernetShow_Click(object sender, EventArgs e)
        {
            this.ethernetShow.Checked = !this.ethernetShow.Checked;
            this.networkMonitorData.FillGrid(this.TUGrid, this.ipv4Show.Checked, this.ipv6Show.Checked, 
                                             this.ethernetShow.Checked, this.Tree.Checked);
            this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.Address], ListSortDirection.Ascending);

            this.EnableTree();

            if (this.Tree.Checked && this.Tree.Enabled)
            {
                this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.Order], ListSortDirection.Ascending);
            }
            else
            {
                this.TUGrid.Columns[(int)GridColumnName.Order].Visible = false;
                this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.TotalBytes], ListSortDirection.Descending);
            }

            SetupGrid();
        }

        /// <summary>
        /// Handle a click of the Mode > "By Conversation" menu item.
        /// </summary>
        private void ModeByConversation_Click(object sender, EventArgs e)
        {
            this.SetCurrentMode(OperationMode.Conversation);
            this.LoadDataAndDisplayGrid();
        }

        /// <summary>
        /// Handle a click of the Mode > "By Endpoint" menu item.
        /// </summary>
        private void ModeByEndpoint_Click(object sender, EventArgs e)
        {
            this.SetCurrentMode(OperationMode.Endpoint);
            this.LoadDataAndDisplayGrid();
        }

        /// <summary>
        /// When the tree menu is pressed, we show different columns.  We add a column,
        /// order, so we can sort on it to reset the original layout.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void Tree_Click(object sender, EventArgs e)
        {
            this.Tree.Checked = !this.Tree.Checked;
            this.networkMonitorData.FillGrid(this.TUGrid, this.ipv4Show.Checked, this.ipv6Show.Checked, 
                                             this.ethernetShow.Checked, this.Tree.Checked);
            this.TUGrid.Sort(this.TUGrid.Columns[(int)GridColumnName.Address], ListSortDirection.Ascending);
            
            if (!Tree.Checked)
            {
                ResetTreeButton.Enabled = false;

                this.TUGrid.Columns[(int)GridColumnName.Order].Visible = false;
                this.TUGrid.Sort(TUGrid.Columns[(int)GridColumnName.TotalBytes], ListSortDirection.Descending);
            }
            else
            {
                ResetTreeButton.Enabled = true;

                this.TUGrid.Sort(TUGrid.Columns[(int)GridColumnName.Order], ListSortDirection.Ascending);
            }

            // Set the width, but not the height.
            Size totSize = TUGrid.PreferredSize;
            totSize.Height = this.Size.Height;
            
            this.Size = totSize;
        }

        /// <summary>
        /// Based on the options selected, we draw the bar chart by having NMCaptureData return a bar
        /// chart control.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void BarChart_Click(object sender, EventArgs e)
        {
            try
            {
                BarChart myBC;

                if (ethernetShow.Checked && !this.networkMonitorData.CheckAddressMapping(ipv4Show.Checked, ipv6Show.Checked))
                {
                    MessageBox.Show(
                                "There are more IP addresses than machines address. Can't create a bar chart when this occurs.", 
                                "Charting Error",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                MessageBoxOptions.DefaultDesktopOnly);
                }
                else
                {
                    myBC = this.networkMonitorData.CreateBarChart(this.ethernetShow.Checked, this.ipv4Show.Checked, this.ipv6Show.Checked);

                    myBC.Show();
                    myBC.Location = this.CenterDialog(myBC.Width);
                }
            }
            catch (System.IO.FileNotFoundException excpt)
            {
                MessageBox.Show(
                                excpt.Message, 
                                "Exception Starting Graphing Component",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                MessageBoxOptions.DefaultDesktopOnly);
                MessageBox.Show(
                                "If this exception was regarding the MSChart DataVisualization control, please install from Microsoft Downloads.  See documentation for more info.", 
                                "Exception Starting Graphing Component",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                MessageBoxOptions.DefaultDesktopOnly);
            }
        }

        /// <summary>
        /// Based on the options selected, we draw the bar chart by having NMCaptureData return a bar
        /// chart control.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void PieChart_Click(object sender, EventArgs e)
        {
            try
            {
                PieChart myPC;

                myPC = this.networkMonitorData.CreatePieChart(this.ethernetShow.Checked, this.ipv4Show.Checked, this.ipv6Show.Checked);

                myPC.Show();
                myPC.Location = this.CenterDialog(myPC.Width);
            }
            catch (System.IO.FileNotFoundException excpt)
            {
                MessageBox.Show(
                                excpt.Message, 
                                "Exception Starting Graphing Component",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                MessageBoxOptions.DefaultDesktopOnly);

                MessageBox.Show(
                                "If this exception was regarding the MSChart DataVisualization control, please install from Microsoft Downloads.  See documentation for more info.",
                                "Exception Starting Graphing Component",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                MessageBoxOptions.DefaultDesktopOnly);
            }
        }

        /// <summary>
        /// When the form is shown, init NmCaptureData, load/parse the capture file, and fill the grid.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void TopUsers_Shown(object sender, EventArgs e)
        {
            try
            {
                TopUsers.ChartControlInstalled();
            }
            catch (System.IO.FileNotFoundException)
            {
                MessageBox.Show(
                            "Unable to load the MSChart DataVisualization control, please install from Microsoft Downloads.  See documentation for more info.",
                            "Exception Loading Graphing Component",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1,
                            MessageBoxOptions.DefaultDesktopOnly);

                this.PieChart.Enabled = false;
                this.BarChart.Enabled = false;
            }

            this.ipv4Show.Checked = true;
            this.ipv6Show.Checked = false;
            this.ethernetShow.Checked = false;
            this.Tree.Checked = false;
            this.ResetTreeButton.Enabled = false;

            for (int n = 2; n < TUGrid.Columns.Count; n++)
            {
                TUGrid.Columns[n].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight;
            }

            // Load and parse the capture file and fill the grid.
            LoadDataAndDisplayGrid();
        }

        /// <summary>
        /// Copies the selected data as TAB separated.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void CopyAsTabSep_Click(object sender, EventArgs e)
        {
            try
            {
                TUGrid.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
                Clipboard.SetDataObject(TUGrid.GetClipboardContent());
            }
            catch (ExternalException exception)
            {
                MessageBox.Show(
                                "Please Report: Error Accessing clipboard " + exception.Message, 
                                "Clipboard Error",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1,
                                MessageBoxOptions.DefaultDesktopOnly);
            }
        }

        /// <summary>
        /// Depending on where the user clicked, capture the grid data and create a filter. If multiple lines are selected,
        /// a complex filter will be created.  Also the filter will changed depending on whether the Conversation or Endpoint
        /// mode is being used.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void CopyAsFilter_Click(object sender, EventArgs e)
        {
            string filter = null;

            if (TUGrid.SelectedRows.Count > 0)
            {
                DataGridViewSelectedRowCollection sr = TUGrid.SelectedRows;

                if (this.mode == OperationMode.Conversation)
                {
                    for (int i = 0; i < sr.Count; i++)
                    {
                        string firstAddress = (string)sr[i].Cells[0].Value;

                        if (!firstAddress.Contains("Entire"))
                        {
                            filter = filter + string.Format(CultureInfo.CurrentCulture, "({0} AND {1})", Address.CreateFilter(firstAddress), Address.CreateFilter((string)sr[i].Cells[1].Value));

                            // If we are on the last one, or the last one is the Entire row entry, don't add an OR.
                            if (i < sr.Count - 1 && !((string)sr[i + 1].Cells[0].Value).Contains("Entire"))
                            {
                                filter += " OR ";
                            }
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < sr.Count; i++)
                    {
                        string firstAddress = (string)sr[i].Cells[0].Value;

                        if (!firstAddress.Contains("Entire"))
                        {
                            filter = filter + string.Format(CultureInfo.CurrentCulture, "{0}", Address.CreateFilter((string)sr[i].Cells[0].Value));

                            // If we are on the last one, or the last one is the Entire row entry, don't add an OR.
                            if (i < sr.Count - 1 && !((string)sr[i + 1].Cells[0].Value).Contains("Entire"))
                            {
                                filter += " OR ";
                            }
                        }
                    }
                }
            }

            if (filter != null)
            {
                Clipboard.SetText(filter);
            }
        }

        /// <summary>
        /// Displays an about box.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox ab = new AboutBox();
            ab.Show();
            ab.Location = this.CenterDialog(ab.Width);
        }

        /// <summary>
        /// Displays the help file, the same one from the NM3 UI.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void GeneralHelpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GenHelp gh = new GenHelp(this.mode == OperationMode.Endpoint);

            gh.Show();
            gh.Location = this.CenterDialog(gh.Width);
        }

        /// <summary>
        /// Resets Tree control to original order
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void ResetTreeButton_Click(object sender, EventArgs e)
        {
            TUGrid.Sort(TUGrid.Columns[(int)GridColumnName.Order], ListSortDirection.Ascending);
        }

        /// <summary>
        /// Determines if the new selection needs to enable/disable the copy
        /// as filter menu.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void TUGrid_SelectionChanged(object sender, EventArgs e)
        {
            if (TUGrid.SelectedRows.Count > 0)
            {
                if (TUGrid.SelectedRows.Count > 1)
                {
                    copyAsFilter.Enabled = true;
                }
                else
                {
                    string val = (string)TUGrid.SelectedRows[0].Cells[0].Value;
                    if (val.Contains("Entire"))
                    {
                        copyAsFilter.Enabled = false;
                    }
                    else
                    {
                        copyAsFilter.Enabled = true;
                    }
                }
            }
            else
            {
                copyAsFilter.Enabled = false;
            }
        }

        /// <summary>
        /// Checks to see if a right click occurs off the original selection.  If it
        /// does, the old selection is removed and the new one selected.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Argument</param>
        private void TUGrid_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                bool inArea = false;
                foreach (DataGridViewCell c in TUGrid.SelectedCells)
                {
                    Rectangle r = TUGrid.GetCellDisplayRectangle(c.ColumnIndex, c.RowIndex, true);
                    if (r.Contains(e.Location))
                    {
                        inArea = true;
                    }
                }

                if (!inArea)
                {
                    TUGrid.ClearSelection();
                    DataGridView.HitTestInfo hti = TUGrid.HitTest(e.X, e.Y);
                    if (hti.Type == DataGridViewHitTestType.Cell)
                    {
                        TUGrid.Rows[hti.RowIndex].Cells[hti.ColumnIndex].Selected = true;
                    }
                    else if (hti.Type == DataGridViewHitTestType.RowHeader)
                    {
                        TUGrid.Rows[hti.RowIndex].Selected = true;
                    }
                }
            }
        }

    }
    #endregion
}

